﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using FZ.Common;
using TongJi.Commmon;
using TongJi.Dal;
using TongJi.Model;

namespace TongJi.Bll
{
    public class TongJiManager
    {
        const string SiteTableCacheKey = "TongJiManager.SiteTable";

        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="context"></param>
        public void InsertRequestLog(HttpContext context)
        {
            string errMsg;
            try
            {
                var model = HandleRequestLogParms(context, out errMsg);
                var dal = new TongJiDal();
                var status = dal.InsertRequestLog(model);
                //context.Response.Write(status ? "1" : "0");
                context.Response.AddHeader(Consts.LogResponseHeaderKey, status ? "success" : "fail");
            }
            catch (Exception ex)
            {
                errMsg = ex.Message;
            }
            if (errMsg != null)
            {
                context.Response.AddHeader(Consts.LogResponseHeaderKey, errMsg);
                // context.Response.Write(errMsg);
            }
        }

        public void AddSite(HttpContext context)
        {
            var Request = context.Request;
            string msg = null;
            var siteName = Request["SiteName"].ToTrim(null);
            var siteDomain = Request["siteDomain"].ToTrim(null);
            if (siteName.IsNullOrWhiteSpace())
            {
                msg = "站点名称不能为空";
            }
            else if (siteDomain.IsNullOrWhiteSpace())
            {
                msg = "站点对应域名不能为空";
            }
            else
            {
                var model = new SiteModel()
                {
                    SiteName = siteName.Trim(),
                    SiteDomain = siteDomain.Trim(),
                    Remark = Request["Remark"],
                    Status = (byte)(Request["Status"] == "1" ? 1 : 0)
                };
                msg = new TongJiDal().AddSite(model).ToString();
            }
            context.Response.Write(msg);
        }

        public void RefreshSiteCache()
        {
            CacheHelper.RemoveCache(SiteTableCacheKey);
        }

        public CheckSiteStatusEnum CheckSiteStatus(HttpContext context, out string msg)
        {
            msg = null;
            var referrer = context.Request.UrlReferrer;
            if (referrer == null)
            {
                msg = "请将此链接放在站点中，不能支持访问！";
                return CheckSiteStatusEnum.Error;
            }

            var siteId = context.Request.QueryString["siteId"].ToInt();
            if (siteId < 0)
            {
                msg = "缺少siteId参数！";
                return CheckSiteStatusEnum.Error;
            }

            DataRow row = null;
            try
            {
                row = GetSiteTable().Select("ID=" + siteId.ToString()).FirstOrDefault();
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return CheckSiteStatusEnum.Tip;
            }
            if (row == null)
            {
                msg = "请先在统计系统中注册站点！";
                return CheckSiteStatusEnum.Error;
            }

            if (row["Status"].ToInt() != 0)
            {
                msg = "站点已停用";
                return CheckSiteStatusEnum.Tip;
            }

            var siteDomain = row["SiteDomain"].ToStringEx();
            if (siteDomain.IsNotNullAndWhiteSpace())
            {
                var arr = siteDomain.Split(',');
                var host = referrer.Host;
                foreach (var item in arr)
                {
                    /*域名相等，或者匹配泛解析*/
                    if (item == host || (item.Contains("*.") && Regex.IsMatch(host, "^" + item.Replace("*.", @"[\s\S]*").Replace(".", "\\.") + "$")))
                    {
                        return CheckSiteStatusEnum.Success;
                    }
                }
                msg = "此域名不在申请的统计站点中！";
                return CheckSiteStatusEnum.Error;
            }

            return CheckSiteStatusEnum.Success;
        }

        #region 工具方法

        public DataTable GetSiteTable()
        {
            var tb = CacheHelper.GetCache(SiteTableCacheKey) as DataTable;
            if (tb == null)
            {
                tb = new TongJiDal().GetSiteTable();
                CacheHelper.SetCache(SiteTableCacheKey, tb);
            }
            return tb;
        }

        /// <summary>
        /// 根据参数构造Model
        /// </summary>
        /// <param name="context"></param>
        /// <param name="errMsg"></param>
        /// <returns></returns>
        private RequestLogModel HandleRequestLogParms(HttpContext context, out string errMsg)
        {
            RequestLogModel model = null;
            errMsg = null;
            var Request = context.Request;

            var userAgent = Request.QueryString["ua"] ?? Request.UserAgent;
            if (userAgent.IsNullOrWhiteSpace())
            {
                errMsg = "userAgent 为空";
                return model;
            }

            var siteId = Request.QueryString["siteId"].ToInt();
            if (siteId < 1)
            {
                errMsg = "siteId 为空";
                return model;
            }

            var userSign = Request.QueryString["us"];
            if (userSign.IsNullOrWhiteSpace())
            {
                errMsg = "userSign 为空";
                return model;
            }

            //var page = Request.QueryString["p"];
            //if (page.IsNullOrWhiteSpace())
            //{
            //    errMsg = "page 为空";
            //    return model;
            //}
            var reqUri = Request.UrlReferrer;
            model = new RequestLogModel()
            {
                SiteId = siteId,
                UserSign = userSign,
                UserAgent = userAgent,
                Ip = Request.UserHostAddress,
                UserName = Request.QueryString["un"],
                UserRole = Request.QueryString["ur"],
                RequestDomain = reqUri.Host,
                RequestUrl = reqUri.ToString(),
                RequestPath = reqUri.AbsolutePath,
                Pcode = WebHelper.GetParmsByUrl(reqUri.Query)["Pcode"],
                Proxy = Request.ServerVariables["X-Forwarded-For"],
                SupportCookie = Request.QueryString["sck"].ToBool(true),
                Platform = Request.QueryString["pf"],
                VisitTime = DateTime.Now
            };

            var screenWH = Request.QueryString["swh"];
            if (Regex.IsMatch(screenWH, @"^\d+x\d+$"))
            {
                var arr = Array.ConvertAll(screenWH.Split('x'), p => int.Parse(p));
                model.AvailWidth = arr[0];
                model.AvailHeight = arr[1];
            }

            var browserWH = Request.QueryString["bwh"];
            if (Regex.IsMatch(browserWH, @"^\d+x\d+$"))
            {
                var arr = Array.ConvertAll(browserWH.Split('x'), p => int.Parse(p));
                model.BrowserWidth = arr[0];
                model.BrowserHeight = arr[1];
            }

            var referrer = Request.QueryString["rf"];
            if (referrer.IsNotNullAndWhiteSpace())
            {
                var rf = new Uri(referrer);
                model.ReferrerUrl = referrer;
                model.ReferrerDomain = rf.Host;
                model.ReferrerPath = rf.AbsolutePath;
            }

            model.System = GetSystem(userAgent, model.Platform);
            model.AgentType = GetAgentType(userAgent);

            var browser = UtilHelper.GetBrowserInfo(userAgent);
            model.BrowserName = browser.BrowserName;
            model.BrowserVersion = browser.BrowserVersion;
            model.BrowserAgentName = browser.BrowserAgentName;
            model.BrowserAgentVersion = browser.BrowserAgentVersion;

            var browserDocMode = Request.QueryString["dm"];
            if (browserDocMode.IsNotNullAndWhiteSpace() && model.BrowserVersion.IsNotNullAndWhiteSpace() && model.BrowserVersion.ToDouble() != browserDocMode.ToDouble())
            {
                model.BrowserDocMode = browserDocMode;
            }
            return model;
        }

        ///// <summary>
        ///// 返回浏览器名称和版本
        ///// </summary>
        ///// <param name="userAgent"></param>
        ///// <returns></returns>
        //private string[] GetBrowserInfo(string userAgent)
        //{
        //    var arr = new string[2];
        //    var dict = new Dictionary<string, string>
        //    {
        //        {"IE", @"msie ([\d.]+)"},
        //        {"Firefox", @"firefox\/([\d.]+)"},
        //        {"Chrome", @"chrome\/([\d.]+)"},
        //        {"Opera", @"opera\/([\d.]+)"},
        //        {"Safari", @"version\/([\d.]+).*safari"}
        //    };

        //    foreach (var item in dict)
        //    {
        //        var t = Regex.Match(userAgent, item.Value, RegexOptions.IgnoreCase);
        //        if (t.Success)
        //        {
        //            arr[0] = item.Key;
        //            arr[1] = t.Groups[1].Value;
        //        }
        //    }
        //    return arr;
        //}

        /// <summary>
        /// 返回终端类型（PC、手机）
        /// </summary>
        /// <param name="userAgent"></param>
        /// <returns></returns>
        private string GetAgentType(string userAgent)
        {
            if (userAgent.Contains("Android"))
            {
                return "Android";
            }
            else if (userAgent.Contains("iPhone"))
            {
                return "iPhone";
            }
            else if (userAgent.Contains("iPad"))
            {
                return "iPad";
            }
            else if (userAgent.Contains("Windows Phone"))
            {
                return "Windows Phone";
            }
            else if (userAgent.Contains("Mobile"))
            {
                return "Mobile";
            }
            else
            {
                return "PC";
            }
        }

        /// <summary>
        /// 返回操作系统
        /// </summary>
        /// <param name="userAgent"></param>
        /// <param name="platform"></param>
        /// <returns></returns>
        private string GetSystem(string userAgent, string platform)
        {
            string _system;
            Func<string, bool> agentInclude = userAgent.Contains;

            if (platform == "Win32" || platform == "Windows" || platform == null)
            {
                if (agentInclude("Windows NT 6.1") || agentInclude("Windows 7"))
                {
                    _system = "Windows 7";
                }
                else if (agentInclude("Windows NT 6.3") || agentInclude("Windows 8.1"))
                {
                    _system = "Windows 8.1";
                }
                else if (agentInclude("Windows NT 6.2") || agentInclude("Windows 8"))
                {
                    _system = "Windows 8";
                }
                else if (agentInclude("Windows NT 6.4") || agentInclude("Windows 10"))
                {
                    _system = "Windows 10";
                }
                else if (agentInclude("Windows NT 5.1") || agentInclude("Windows XP"))
                {
                    _system = "Windows XP";
                }
                else if (agentInclude("Windows NT 5.2") || agentInclude("Windows 2003"))
                {
                    _system = "Windows 2003";
                }
                else if (agentInclude("Windows NT 6.0") || agentInclude("Windows Vista"))
                {
                    _system = "Windows Vista";
                }
                else if (agentInclude("Windows Phone"))
                {
                    var t = Regex.Match(userAgent, "Windows Phone [^;]+?;");
                    if (t.Success)
                    {
                        _system = t.Groups[0].Value;
                    }
                    else
                    {
                        _system = "Windows Phone";
                    }
                }
                else if (agentInclude("Windows NT 5.0") || agentInclude("Windows 2000"))
                {
                    _system = "Windows 2000";
                }
                else
                {
                    _system = platform == null ? "" : "unknown Windows";
                }
            }
            else if (platform == "Mac68K" || platform == "MacPPC" || platform == "Macintosh" || platform == "MacIntel")
            {
                _system = "mac";
            }
            else if (platform == "X11")
            {
                _system = "unix";
            }
            else if (platform.Contains("Linux"))
            {
                _system = "linux";
            }
            else
            {
                _system = "";
            }
            return _system;
        }
        #endregion
    }
}
